package sw6.visualschedule.persistence;

import com.j256.ormlite.misc.TransactionManager;
import com.j256.ormlite.stmt.PreparedQuery;
import com.j256.ormlite.stmt.QueryBuilder;

import sw6.visualschedule.entities.ActivityStatus;
import sw6.visualschedule.entities.DbDate;
import sw6.visualschedule.entities.RepeatPattern;
import sw6.visualschedule.entities.ScheduleActivity;
import sw6.visualschedule.entities.Step;

import android.content.Context;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Callable;

public class ScheduleActivityRepo extends AbstractDataRepo<ScheduleActivity> {

    private static final String LOG_NAME = "ScheduleActivityService";
    private final transient ActivityStatusRepo mActivityStatusService;
    private final transient DateRepo mDateService;
    private final transient RepeatPatternRepo mRepeatPatternService;
    
    private final transient StepRepo mStepService;
    
    /**
     * Initializes the repository.
     * @param base the context to run in.
     */
    public ScheduleActivityRepo(final Context base) {
        super(ScheduleActivity.class);
        
        this.attachBaseContext(base);
        
        mStepService = new StepRepo(base);
        mDateService = new DateRepo(base);
        mRepeatPatternService = new RepeatPatternRepo(base);
        mActivityStatusService = new ActivityStatusRepo(base);
    }
    
    @Override
    public void delete(final int itemId) {
        final ScheduleActivity act = getById(itemId);
        delete(act);
    }
    
    @Override
    public void delete(final ScheduleActivity obj) {
        try {
            TransactionManager.callInTransaction(getConnectionSource(), new Callable<Void>() {
                @Override
                public Void call() throws Exception {
                    
                    for (Step s : obj.getSteps()) {
                        mStepService.delete(s);
                    }
                    
                    for (DbDate d : obj.getDates()) {
                         mDateService.delete(d);
                    }
                 
                    for (RepeatPattern r : obj.getRepeatPatterns()) {
                        mRepeatPatternService.delete(r);
                    }
                    
                    mActivityStatusService.delete(obj.getId());

                    superDelete(obj);
                    
                    return null;
                }
            });
        } catch (SQLException e) {
        	throw new RuntimeException(LOG_NAME, e);
        }
    }
    
    /**
     * Returns a list of activities for a specific date.
     * Gets data from date and repeat pattern repositories.
     * @param date the date to filter by.
     * @return a list of activities.
     */
    public List<ScheduleActivity> getActivities(final Date date) {
        final List<ScheduleActivity> activities = new ArrayList<ScheduleActivity>();
        
        activities.addAll(mDateService.getActivities(date));
        activities.addAll(mRepeatPatternService.getActivities(date));
         
        Collections.sort(activities);
        
        final List<ActivityStatus> statusEntries = mActivityStatusService.getStatusEntries(date);
        
        // TODO: Lav forsøg om nedenstående er hurtigere/langsommere end at lave et separat query til hver activity
        final HashMap<String, Integer> positionMap = new HashMap<String, Integer>();
        for (int i = 0; i < activities.size(); i++) {
            positionMap.put(activities.get(i).getId() + activities.get(i).getInstanceDate().toString(), i);
        }
        
        Integer currPosition;
        for (ActivityStatus statusEntry : statusEntries) {
            currPosition = positionMap.get(statusEntry.getActivity().getId() + statusEntry.getDateTime().toString()); // laver .getActivity().getId() et query? 
            if (currPosition != null) {
                activities.get(currPosition).setInstanceStatus(statusEntry.getStatus());
            }
        }
        
        return activities;
    }
    
    /**
     * Returns a list of all spontaneous activities.
     * @return a list of spontaneous activities.
     */
    public List<ScheduleActivity> getSpontaneousActivities() {
        List<ScheduleActivity> entries = new ArrayList<ScheduleActivity>();
        
        try {
            final QueryBuilder<ScheduleActivity, Integer> query = getDao().queryBuilder();
            
            query.where().eq(ScheduleActivity.SPONTANEOUS_FIELD, true);
            query.orderBy(ScheduleActivity.TITLE_FIELD, true);
            
            final PreparedQuery<ScheduleActivity> preparedQuery = query.prepare();
            
            entries = getDao().query(preparedQuery);
            
        } catch (SQLException e) {
        	throw new RuntimeException(LOG_NAME, e);
        }
        
        return entries;
    }
    
    private void superDelete(final ScheduleActivity obj) {
        super.delete(obj);        
    }
}	